using System;
using System.Collections.Generic;
using System.ComponentModel;
using DevExpress.XtraEditors;
using CSW.Framework.Common;
using CSW.Framework.Common.Binding;
using CSW.Framework.Common.Binding.Interfaces;

namespace CSW.Framework.UI.DevEx.UserControls
{
    /// <summary>
    /// Multi-select user control.
    /// </summary>
    public partial class DXMultiSelectUserControl : XtraUserControl
    {
        private IDataSelectionList m_DataList;
        private bool m_ReadOnly;

        /// <summary>
        /// Initializes a new instance of the <see cref="DXMultiSelectUserControl"/> class.
        /// </summary>
        public DXMultiSelectUserControl()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Gets the data list.
        /// </summary>
        /// <value>The data list.</value>
        public IDataSelectionList DataList
        {
            get 
            {
                Guard.ArgumentNotNull(m_DataList, "m_DataList");
                return m_DataList; 
            }
        }

        /// <summary>
        /// Gets a value indicating whether this instance is read only.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is read only; otherwise, <c>false</c>.
        /// </value>
        public bool IsReadOnly
        {
            get { return m_ReadOnly; }
        }

        /// <summary>
        /// Setup the specified initial list.
        /// </summary>
        /// <param name="initialList">The initial list.</param>
        /// <param name="selectedItems">The selected items.</param>
        /// <param name="headers">The column headers.</param>
        /// <param name="fields">The fields.</param>
        /// <param name="isReadOnly">if set to <c>true</c>, the list is read only.</param>
        public void Setup<T>(BindingList<T> initialList, BindingList<T> selectedItems, IList<string> headers, IList<string> fields, bool isReadOnly) 
            where T : INotifyPropertyChanged
        {
            Guard.ArgumentNotNull(initialList, "initialList");
            Guard.ArgumentNotNull(selectedItems, "selectedItems");
            Guard.ArgumentNotNullOrEmpty(headers, "headers");
            Guard.ArgumentNotNullOrEmpty(fields, "fields");

            DataSelectionList<T> dataSelectionList = new DataSelectionList<T>(initialList, selectedItems);

            Setup(dataSelectionList, headers, fields, isReadOnly);
        }

        /// <summary>
        /// Setups the specified initial list.
        /// </summary>
        /// <param name="dataList">The data list.</param>
        /// <param name="headers">The column headers.</param>
        /// <param name="fields">The fields.</param>
        /// <param name="isReadOnly">if set to <c>true</c>, the list is read only.</param>
        internal void Setup(IDataSelectionList dataList, IList<string> headers, IList<string> fields, bool isReadOnly)
        {
            Guard.ArgumentNotNull(dataList, "dataList");
            Guard.ArgumentNotNullOrEmpty(headers, "headers");
            Guard.ArgumentNotNullOrEmpty(fields, "fields");

            m_DataList = dataList;

            // Do the initialization with a dummy TypedGridController
            // We don't know the type in this situation

            TypedGridController<INotifyPropertyChanged> availableGrid = new TypedGridController<INotifyPropertyChanged>(grdAvailable, "AvailableItems");
            TypedGridController<INotifyPropertyChanged> selectedGrid = new TypedGridController<INotifyPropertyChanged>(grdSelected, "SelectedItems");
            
            // Add headers to grids
            for (int i = 0; i < headers.Count; i++)
            {
                availableGrid.AddField(headers[i], fields[i]);
                selectedGrid.AddField(headers[i], fields[i]);
            }
            //availableGrid.Setup();
            //selectedGrid.Setup();

            grdAvailable.DataSource = dataList.AvailableItems;
            grdSelected.DataSource = dataList.SelectedItems;

            grvAvailable.BestFitColumns();
            grvSelected.BestFitColumns();

            m_ReadOnly = isReadOnly;
            if (m_ReadOnly)
            {
                btnAddSelected.Visible = false;
                btnAddAll.Visible = false;
                btnRemoveSelected.Visible = false;
                btnRemoveAll.Visible = false;
            }
        }

        private void btnSelectAll_Click(object sender, EventArgs e)
        {
            Guard.ArgumentNotNull(m_DataList, "m_DataList");

            if (m_ReadOnly)
                return;

            m_DataList.SelectAll();
        }

        private void btnSelect_Click(object sender, EventArgs e)
        {
            AddSelected();
        }

        private void AddSelected()
        {
            Guard.ArgumentNotNull(m_DataList, "m_DataList");

            if (m_ReadOnly)
                return;

            List<object> items = new List<object>();
            foreach (int rowHandle in grvAvailable.GetSelectedRows())
            {
                object item = grvAvailable.GetRow(rowHandle);
                items.Add(item);
            }

            foreach (object item in items)
                m_DataList.SelectItem(item);
        }

        private void btnDeselect_Click(object sender, EventArgs e)
        {
            RemoveSelected();
        }

        private void RemoveSelected()
        {
            Guard.ArgumentNotNull(m_DataList, "m_DataList");

            if (m_ReadOnly)
                return;

            List<object> items = new List<object>();
            foreach (int rowHandle in grvSelected.GetSelectedRows())
            {
                object item = grvSelected.GetRow(rowHandle);
                items.Add(item);
            }

            foreach (object item in items)
                m_DataList.DeselectItem(item);
        }

        private void btnDeselectAll_Click(object sender, EventArgs e)
        {
            Guard.ArgumentNotNull(m_DataList, "m_DataList");

            if (m_ReadOnly)
                return;

            m_DataList.DeselectAll();
        }

        private void grdAvailable_RowDoubleClick(object sender, RowDoubleClickEventArgs e)
        {
            AddSelected();
        }

        private void grdSelected_RowDoubleClick(object sender, RowDoubleClickEventArgs e)
        {
            RemoveSelected();
        }
    }
}
